package com.icw.resource.inner.initialization;

import static com.icw.configuration.ConstSettings.DEFAULT_PASSWORD;
import static com.icw.configuration.ConstSettings.DEFAULT_USERNAME;
import static com.icw.configuration.ConstSettings.NAME_OF_ADMIN_ROLE;
import static com.icw.configuration.ConstSettings.NAME_OF_DEFAULT_ROLE;

import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.Map.Entry;
import java.util.stream.Collectors;
import java.util.stream.Stream;

import org.apache.commons.lang3.ArrayUtils;

import com.icw.basis.ModuleInitialization;
import com.icw.basis.PropertySettings;
import com.icw.decoupling.defi.proxy.GenericSrvProxy;
import com.icw.decoupling.defi.tool.DataExchange;
import com.icw.decoupling.defi.tool.DictManager;
import com.icw.decoupling.defi.tool.TimerJobManager;
import com.icw.resource.inner.entity.IcwMenu;
import com.icw.resource.inner.entity.IcwPerm;
import com.icw.resource.inner.entity.IcwRole;
import com.icw.resource.inner.entity.IcwUser;
import com.icw.utility.BeanCtxUtils;
import com.icw.utility.IcwUtils;
import com.icw.utility.PoEntityHelper;
import com.icw.utility.query.IcwCriteria;

public class IcwModuleInitialization extends ModuleInitialization {

	@Override
	public String modulePrefix() {
		return "icw";
	}

	@Override
	public void initialize() throws Exception {
		DictManager.defaultInit();
		// F. initial dict entity type
		DictManager.entityTypeInit();
		// -. initial default role
		initialDefaultAdminRole();
		// -. initial admin user / role / perm
		initialAdminUser();
		// -. initial menu
		initialModuleMenus();
		// L. initial dict cache
		DictManager.initDictCache();
		// -. initial quatz persist data and start all.
		TimerJobManager.persistData();
		TimerJobManager.startAll();
		// temporary
	}

	private void initialDefaultAdminRole() throws Exception {
		initialRole(NAME_OF_DEFAULT_ROLE, (pi) -> pi.permSettings());
		initialRole(NAME_OF_ADMIN_ROLE, (pi) -> pi.adminSettings());
		initialPermsOfAdmin();
	}

	private void initialPermsOfAdmin() throws Exception {
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		IcwRole adminRole = srv.findByName(IcwRole.class, NAME_OF_ADMIN_ROLE);
		Set<Class<PropertySettings<?>>> pses = PoEntityHelper.getPropertySettings();
		for (Class<?> ps : pses) {
			PropertySettings<?> pi = PropertySettings.class.cast(ps.getConstructor().newInstance());
			String[] lp = pi.listProperties();
			if (lp != null && lp.length != 0 && srv.countByCriteria(IcwPerm.class, new IcwCriteria(// e
					"eq", "roles.id", adminRole.getId(), // e
					"eq", "route", __permRoute(pi.getEntityClass(), "getlist"))// e
			) == 0) {
				IcwUtils.mgrSave(IcwPerm.class, IcwUtils.mapObject(null, null// e
						, "name", __permName(pi.getEntityClass(), "getlist", NAME_OF_ADMIN_ROLE)// e
						, "route", __permRoute(pi.getEntityClass(), "getlist")// e
						, "paramsLimits", ""// e
						, "roles", new Object[] { IcwUtils.idObj(adminRole) }// e
				));
			}
		}
	}

	private String __permRoute(Class<?> entityClass, String action) {
		return String.format("/resource/%s/%s", IcwUtils.toFirstLowerCase(entityClass.getSimpleName()), action);
	}

	private IcwRole initialRole(String name, PS_ROLE pr) throws Exception {
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		DataExchange de = BeanCtxUtils.getBeanByType(DataExchange.class);
		IcwRole role = srv.findByName(IcwRole.class, name);
		if (role == null) {
			role = IcwUtils.mgrSave(IcwRole.class, IcwUtils.mapObject("name", name));
		}
		Set<Class<PropertySettings<?>>> pses = PoEntityHelper.getPropertySettings();
		for (Class<?> ps : pses) {
			PropertySettings<?> pi = PropertySettings.class.cast(ps.getConstructor().newInstance());
			Map<String, Map<String, Object>> permSettings = pr.func(pi);
			if (permSettings != null) {
				for (Entry<String, Map<String, Object>> entry : permSettings.entrySet()) {
					Map<String, Object> kvs = entry.getValue();
					List<Object> limits = IcwUtils.listObj();
					if (kvs != null) {
						for (Entry<String, Object> ety : kvs.entrySet()) {
							limits.add(IcwUtils.mapObject("k", ety.getKey(), "v", ety.getValue()));
						}
					}
					String route = __permRoute(pi.getEntityClass(), entry.getKey());
					if (srv.countByCriteria(IcwPerm.class, new IcwCriteria("eq", "route", route, "eq", "roles.name", name)) == 0) {
						IcwUtils.mgrSave(IcwPerm.class, IcwUtils.mapObject(null, null// e
								, "name", __permName(pi.getEntityClass(), entry.getKey(), name)// e
								, "route", route// e
								, "paramsLimits", de.serialize(limits)// e
								, "roles", new Object[] { IcwUtils.idObj(role) }// e
						));
					}
				}
			}
		}
		return role;
	};

	private String __permName(Class<?> entityClass, String action, String roleName) {
		return entityClass.getSimpleName() + "-" + action + "-" + roleName;
	}

	private interface PS_ROLE {

		Map<String, Map<String, Object>> func(PropertySettings<?> pi);
	}

	private void initialAdminUser() throws Exception {
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		IcwUser adminUser;
		adminUser = srv.findByName(IcwUser.class, DEFAULT_USERNAME);
		if (adminUser == null) {
			adminUser = IcwUtils.mgrSave(IcwUser.class, IcwUtils.mapObject(null, null// e
					, "username", DEFAULT_USERNAME// e
					, "password", DEFAULT_PASSWORD// e
					, "roles", new Object[] { IcwUtils.idObj(srv.findByName(IcwRole.class, NAME_OF_ADMIN_ROLE)) }// e
			));
		}
	}

	private void initialModuleMenus() throws Exception {
		GenericSrvProxy srv = BeanCtxUtils.getBeanByType(GenericSrvProxy.class);
		List<?> list = srv.query(IcwPerm.class, new IcwCriteria("like", "route", "%getlist", "group", "route", "group_concat(1)", "id"), null);
		for (Object temp : list) {
			String route = (String) PoEntityHelper.readValueByProperty(temp, "values[0]");
			Object[] objs = Stream.of(PoEntityHelper.toObjectArray(PoEntityHelper.readValueByProperty(temp, "values[1]")))// e
					.filter(s -> s != null && !"".equals(s) && !"null".equals(s))// e
					.map(s -> IcwUtils.idObj(s)).toArray();
			String[] parts = Stream.of(route.split("/")).filter(s -> !"".equals(s)).collect(Collectors.toList()).toArray(ArrayUtils.toArray());
			String resourceName = parts[1];
			String resourceUnderScore = IcwUtils.toUnderScoreCase(resourceName);
			String menuRoute = String.format("/index/rsrc/%s/list", resourceUnderScore);
			if (srv.countByCriteria(IcwMenu.class, new IcwCriteria("eq", "route", menuRoute)) == 0) {
				String menuParentName = resourceUnderScore.substring(0, resourceUnderScore.indexOf("_")).toUpperCase();
				IcwMenu menuParent = srv.findByName(IcwMenu.class, menuParentName);
				if (menuParent == null) {
					menuParent = IcwUtils.mgrSave(IcwMenu.class, IcwUtils.mapObject("name", menuParentName));
				}
				IcwUtils.mgrSave(IcwMenu.class, IcwUtils.mapObject(null, null// e
						, "name", resourceUnderScore.substring(resourceUnderScore.indexOf("_") + 1).replaceAll("_", " ").toUpperCase()// e
						, "route", menuRoute// e
						, "parent", IcwUtils.idObj(menuParent)// e
						, "perms", objs // e
				));
			}
		}
	}
}
